package com.xinchao.job.service.asynccomment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.mail.MessagingException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.xinchao.common.model.advertise.*;
import com.xinchao.job.mapper.dmp.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import com.alibaba.fastjson.JSONObject;
import com.xinchao.common.bo.DeviceReportBO;
import com.xinchao.common.constant.BusinessConstant;
import com.xinchao.common.constant.CacheConstant;
import com.xinchao.common.model.WarnLog;
import com.xinchao.common.sms.SmsTemplateType;
import com.xinchao.common.util.EmailUtil;
import com.xinchao.common.util.HuaWeiSmsUtil;
import com.xinchao.common.util.ListUtil;
import com.xinchao.common.vo.AdministratorVO;
import com.xinchao.common.vo.DeviceOffLineVO;
import com.xinchao.core.cache.redis.RedisCacheDao;

import static com.xinchao.common.util.DateUtils.stringTimeToLongTimeStamp;

@Component
public class AsyncCommentService  {
	private static Logger logger = LoggerFactory.getLogger(AsyncCommentService.class);
	@Autowired
	private DeviceInfoMapper deviceInfoMapper;
	@Autowired
	private DeviceSimInfoMapper deviceSimInfoMapper;
	@Autowired
	private RedisCacheDao redisCacheDao;
	@Autowired
	private DeviceWarnLogMapper deviceWarnLogMapper;

	@Value("${xc.sms.huawei.callback.url}")
    private String sendStatusCallBackUrl;
	@Value("${xc.device.report.cache.hash.size}")
    private Integer hashEntrySize;
	
	@Async
	public void batchSyncDeviceReport(List<DeviceReportBO> reports) {
		StopWatch stopWatch = new StopWatch();  
		stopWatch.start();
		// 考虑到可能每个桶中的终端数据较多批量更新可能出现问题，此处每次更新500条数据 
		List<List<DeviceReportBO>> singleLimitAssign = ListUtil.singleLimitAssign(reports, 500);
		Map<String,Object> params = new HashMap<>();
		for ( List<DeviceReportBO> list : singleLimitAssign ) {
			params.clear();
			params.put("list", list);
			deviceInfoMapper.batchUpDeviceReport(params);
			deviceSimInfoMapper.batchUpDeviceSimInfoReport(params);
		}
		stopWatch.stop();
		//logger.debug(" >> batchSyncDeviceReport execute " + stopWatch.getTotalTimeSeconds());
	}
	
	@Async
	public void handleOfflineDevice(List<DeviceOffLineVO> offLineDeviceList, Map<Object, Object> adminUserMap) {
		
		// 记录处理离线设备的deviceCode
		List<String> deviceCodes = new ArrayList<>();
		for ( DeviceOffLineVO device : offLineDeviceList ) {
			deviceCodes.add(device.getDeviceCode());

			// 记录异常离线添加报警日志并发送提醒短信或邮件
			if ( Boolean.TRUE.equals(device.getUnExpectedOffLine()) )  {
				logger.warn(" == job任务开始处理异常离线设备:" + device.getDeviceCode());

				// 更新离线设备的缓存信息
				try {
					updateDeviceCacheStatus(device);
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("设备【"+device.getDeviceCode()+"】异常离线，更新缓存异常：" + e.getMessage(),e);
				}
				try {
					addWarnLogRecord(device,adminUserMap);
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("设备【"+device.getDeviceCode()+"】异常离线，添加报警日志异常：" + e.getMessage(),e);
				}
			}
		}
		
		// 3、统一批量更新数据库设备状态为“离线”
		deviceInfoMapper.batchUpDeviceOffLineByDeviceCode(deviceCodes);
	}
	
	private void updateDeviceCacheStatus(DeviceOffLineVO device) {
		redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_NUM_ONLINE_STATUS, device.getDeviceNum(), BusinessConstant.DEVICE_INFO_STATUS_OFF_LINE);
	}
	
	private void addWarnLogRecord(DeviceOffLineVO device, Map<Object, Object> userMap) {
		String userIds = device.getAdministrator();
		if ( StringUtils.isNotBlank(userIds) && !userMap.isEmpty()) {
			String[] split = userIds.split(",");
			for ( String s : split ) {
				String location = new StringBuilder("").append(device.getProvince()).append(device.getCity()).append(device.getDistrict()).append(device.getDetailAddress()).toString();
				String tipMsg = String.format(BusinessConstant.DEVICE_OFF_LINE_TIPS, location,device.getDeviceNum());
				AdministratorVO user = (AdministratorVO) userMap.get(s);
				if ( user != null && StringUtils.isNotBlank(user.getMobile()) ) {
					String[] params = { location,device.getDeviceNum()};
					
					// 发送短信
					Map<String, Object> returnMap = HuaWeiSmsUtil.sendSMS(SmsTemplateType.DEVICE_UNEXPECTED_OFF_LINE.getTemplateId(), JSONObject.toJSONString(params), user.getMobile(), sendStatusCallBackUrl);
					WarnLog warnLog = new WarnLog(device.getDeviceCode(), s, user.getMobile(), null, tipMsg, System.currentTimeMillis(), 
							BusinessConstant.TIPS_TYPE_DEVICE_OFF_LINE, device.getCity(),BusinessConstant.SEND_STATUS_FAILURE,returnMap.get("smsMsgId").toString());
					
					// 保存发送记录
					deviceWarnLogMapper.insertWarnLog(warnLog);
				}
				if ( user != null && StringUtils.isNotBlank(user.getEmail()) ) {
					Integer sendFlag = BusinessConstant.SEND_STATUS_FAILURE;
					
					// 发送邮件
					try {
						EmailUtil.sendMail(tipMsg, "设备异常离线通知", user.getEmail());
					} catch (MessagingException | IOException e) {
						logger.error(e.getMessage(),e);
						e.printStackTrace();
					}
					sendFlag = BusinessConstant.SEND_STATUS_SUCCESS;
					WarnLog warnLog = new WarnLog(device.getDeviceCode(), s, null, user.getEmail(), tipMsg, System.currentTimeMillis(), 
							BusinessConstant.TIPS_TYPE_DEVICE_OFF_LINE, device.getCity(),sendFlag);
					
					// 保存发送记录
					deviceWarnLogMapper.insertWarnLog(warnLog);
				}
			}
		}
	}
}
